package cfiles

import (
	"context"
	"fmt"
	"gomeshsync/cfile"
	"gomeshsync/config"
	"gomeshsync/consts"
	"io"
	"log"
	"math"
	"net"
	"time"

	"gitee.com/kimsoso/go-utils/sonet"
	"github.com/vmihailenco/msgpack"
)

func StartFinder(ctx context.Context) {
	conf := config.GetConfig()
	for {
		nodes := config.GetNodes()
		if len(nodes) > 0 {
			threadCount := int(math.Min(float64(len(config.GetNodes())-1), float64(conf.Threads)))
			for i := 0; i < threadCount; i++ {
				go FindRemoteNewCmds(ctx)
			}
			return
		}
		time.Sleep(time.Millisecond * 100)
	}
}

// 搜索远程服务器命令序列
func FindRemoteNewCmds(ctx context.Context) {
	conf := config.GetConfig()
	for {
		// 根据情况阻塞线程
		<-ChanStockCmds

		node := config.GetNextNode()

		if node != "" {

			select {
			case <-ctx.Done():
				return
			default:
				remoteNodeCmdsBuf, err := searchRemoteNodeCommands(node, conf)
				if err != nil || len(remoteNodeCmdsBuf) == 0 {
					conf.Sleep()
					continue
				}

				remoteNodeCmds := []*cfile.MCommand{}
				err = msgpack.Unmarshal(remoteNodeCmdsBuf, &remoteNodeCmds)
				if err == nil {
					saveNewCmdsToDisk(remoteNodeCmds) //存储新命令到本地
				} else {
					log.Println("can't parse remote files strings:", err)
				}
			}
		}

		conf.Sleep()
	}
}

//搜索远端节点的命令数据
func searchRemoteNodeCommands(node string, conf *config.Config) (remoteNodeCmdsBuf []byte, err error) {
	// 建立连接
	conn, err := timeoutConn(node, conf.DataPort)
	if err != nil {
		log.Println("connect to "+node+" error", err)
		return nil, err
	}
	defer conn.Close()

	// command: 发送请求文件列表到接收端
	err = sonet.Write(conn, []byte(fmt.Sprintf("%s:%d", consts.COMM_REQNEWFILE, MainCmds.Nextkey())))
	if err != nil {
		log.Println("conn.Write err", err)
		return nil, err
	}

	// log.Println("searchRemoteNodeCommands nextkey is:", MainCmds.Nextkey())

	// 接收服务器返还的文件列表
	_, remoteNodeCmdsBuf, err = sonet.Read(conn)
	if err == io.EOF {
		return nil, err
	}
	if err != nil {
		log.Println("conn.Read err:", err)
		return
	}
	return remoteNodeCmdsBuf, nil
}

// 将远端命令存储到本地
func saveNewCmdsToDisk(remoteNodeCmds []*cfile.MCommand) (haveNewCmds bool) {
	TempCmds.Lock()
	defer TempCmds.Unlock()

	//过滤本地已存在的数据
	if remoteNodeCmds[0].Ck != int(MainCmds.Nextkey()) {
		return false
	}

	return createTemporaryCmds(remoteNodeCmds) == nil
}

/**
 * @description: 结束当前运行命令，并检查是否所有命令都顺序完成，所有命令完成后删除当前命令序列
 * @param {*MCommand} cmd
 * @return {*}
 */
func setCommandDone(cmd *cfile.MCommand) {
	TempCmds.Lock()
	defer TempCmds.Unlock()

	cmd.Done = true
	cmd.DoneTime = time.Now().Unix()
	TempCmds.Update(cmd)
	log.Println("current done command key is: ", cmd.Ck)
}

// 带超时的连接
func timeoutConn(ip string, port int) (conn net.Conn, err error) {
	dialer := net.Dialer{Timeout: time.Second * consts.SocketTimeout}
	return dialer.Dial("tcp", fmt.Sprintf("%s:%d", ip, port))
}
